"""
Intel HEX文件解析器模块
用于解析hex文件并转换为bin格式数据
"""

import os
from typing import Tuple, Dict, List, Optional


class HexRecord:
    """HEX记录类"""
    def __init__(self, data_length: int, address: int, record_type: int, data: bytes, checksum: int):
        self.data_length = data_length
        self.address = address
        self.record_type = record_type
        self.data = data
        self.checksum = checksum


class HexParser:
    """Intel HEX文件解析器"""
    
    # 记录类型定义
    RECORD_TYPE_DATA = 0x00          # 数据记录
    RECORD_TYPE_EOF = 0x01           # 文件结束记录
    RECORD_TYPE_EXTENDED_SEGMENT = 0x02  # 扩展段地址记录
    RECORD_TYPE_START_SEGMENT = 0x03     # 开始段地址记录
    RECORD_TYPE_EXTENDED_LINEAR = 0x04   # 扩展线性地址记录
    RECORD_TYPE_START_LINEAR = 0x05      # 开始线性地址记录
    
    def __init__(self):
        self.records = []
        self.data_records = []
        self.binary_data = bytearray()
        self.min_address = None
        self.max_address = None
        self.file_path = ""
        
    def parse_file(self, file_path: str) -> bool:
        """解析HEX文件"""
        try:
            self.file_path = file_path
            self.records = []
            self.data_records = []
            self.binary_data = bytearray()
            self.min_address = None
            self.max_address = None
            
            with open(file_path, 'r', encoding='utf-8') as f:
                lines = f.readlines()
            
            extended_address = 0
            
            for line_num, line in enumerate(lines, 1):
                line = line.strip()
                if not line:
                    continue
                    
                if not line.startswith(':'):
                    raise ValueError(f"行 {line_num}: 无效的HEX记录格式 - 必须以':'开始")
                
                # 解析记录
                record = self._parse_record(line, line_num)
                self.records.append(record)
                
                # 处理不同类型的记录
                if record.record_type == self.RECORD_TYPE_DATA:
                    # 数据记录
                    actual_address = extended_address + record.address
                    self.data_records.append((actual_address, record.data))
                    
                    # 更新地址范围
                    if self.min_address is None or actual_address < self.min_address:
                        self.min_address = actual_address
                    end_address = actual_address + len(record.data) - 1
                    if self.max_address is None or end_address > self.max_address:
                        self.max_address = end_address
                        
                elif record.record_type == self.RECORD_TYPE_EXTENDED_LINEAR:
                    # 扩展线性地址记录
                    if len(record.data) != 2:
                        raise ValueError(f"行 {line_num}: 扩展线性地址记录数据长度错误")
                    extended_address = (record.data[0] << 24) | (record.data[1] << 16)
                    
                elif record.record_type == self.RECORD_TYPE_EXTENDED_SEGMENT:
                    # 扩展段地址记录
                    if len(record.data) != 2:
                        raise ValueError(f"行 {line_num}: 扩展段地址记录数据长度错误")
                    extended_address = ((record.data[0] << 8) | record.data[1]) << 4
                    
                elif record.record_type == self.RECORD_TYPE_EOF:
                    # 文件结束记录
                    break
            
            # 构建连续的二进制数据
            self._build_binary_data()
            return True
            
        except Exception as e:
            print(f"解析HEX文件失败: {str(e)}")
            return False
    
    def _parse_record(self, line: str, line_num: int) -> HexRecord:
        """解析单个HEX记录"""
        try:
            # 移除冒号
            hex_data = line[1:]
            
            # 验证长度
            if len(hex_data) < 10:  # 最小长度：2(长度) + 4(地址) + 2(类型) + 2(校验和)
                raise ValueError("记录长度不足")
            
            # 解析各字段
            data_length = int(hex_data[0:2], 16)
            address = int(hex_data[2:6], 16)
            record_type = int(hex_data[6:8], 16)
            
            # 计算预期总长度
            expected_length = 8 + (data_length * 2) + 2  # 8(头部) + 数据 + 2(校验和)
            if len(hex_data) != expected_length:
                raise ValueError(f"记录长度不匹配，预期 {expected_length}，实际 {len(hex_data)}")
            
            # 提取数据
            data = bytes.fromhex(hex_data[8:8 + (data_length * 2)])
            checksum = int(hex_data[-2:], 16)
            
            # 验证校验和
            calculated_checksum = self._calculate_checksum(data_length, address, record_type, data)
            if checksum != calculated_checksum:
                raise ValueError(f"校验和错误，计算值: 0x{calculated_checksum:02X}，记录值: 0x{checksum:02X}")
            
            return HexRecord(data_length, address, record_type, data, checksum)
            
        except Exception as e:
            raise ValueError(f"行 {line_num}: {str(e)}")
    
    def _calculate_checksum(self, data_length: int, address: int, record_type: int, data: bytes) -> int:
        """计算校验和"""
        checksum = data_length + (address >> 8) + (address & 0xFF) + record_type
        for byte in data:
            checksum += byte
        return (0x100 - (checksum & 0xFF)) & 0xFF
    
    def _build_binary_data(self):
        """构建连续的二进制数据"""
        if not self.data_records or self.min_address is None or self.max_address is None:
            return
        
        # 计算总大小
        total_size = self.max_address - self.min_address + 1
        self.binary_data = bytearray(total_size)
        
        # 填充数据
        for address, data in self.data_records:
            offset = address - self.min_address
            for i, byte in enumerate(data):
                self.binary_data[offset + i] = byte
    
    def get_binary_data(self) -> bytes:
        """获取转换后的二进制数据"""
        return bytes(self.binary_data)
    
    def get_file_properties(self) -> Dict:
        """获取文件属性"""
        properties = {
            "文件路径": self.file_path,
            "文件名": os.path.basename(self.file_path) if self.file_path else "",
            "文件大小(字节)": os.path.getsize(self.file_path) if self.file_path and os.path.exists(self.file_path) else 0,
            "记录总数": len(self.records),
            "数据记录数": len(self.data_records),
            "起始地址": f"0x{self.min_address:08X}" if self.min_address is not None else "N/A",
            "结束地址": f"0x{self.max_address:08X}" if self.max_address is not None else "N/A",
            "地址范围": f"0x{self.max_address - self.min_address + 1:X}" if self.min_address is not None and self.max_address is not None else "N/A",
            "二进制数据大小": len(self.binary_data),
            "文件类型": "Intel HEX",
            "是否有效": len(self.binary_data) > 0
        }
        
        # 计算简单校验和
        if self.binary_data:
            checksum = sum(self.binary_data) & 0xFFFFFFFF
            properties["数据校验和"] = f"0x{checksum:08X}"
        else:
            properties["数据校验和"] = "N/A"
        
        return properties
    
    def validate_file(self, file_path: str) -> Tuple[bool, str]:
        """验证HEX文件格式"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                lines = f.readlines()
            
            if not lines:
                return False, "文件为空"
            
            record_count = 0
            has_eof = False
            
            for line_num, line in enumerate(lines, 1):
                line = line.strip()
                if not line:
                    continue
                
                if not line.startswith(':'):
                    return False, f"行 {line_num}: 无效的HEX记录格式"
                
                try:
                    record = self._parse_record(line, line_num)
                    record_count += 1
                    
                    if record.record_type == self.RECORD_TYPE_EOF:
                        has_eof = True
                        break
                        
                except Exception as e:
                    return False, f"行 {line_num}: {str(e)}"
            
            if record_count == 0:
                return False, "没有找到有效的HEX记录"
            
            if not has_eof:
                return False, "文件缺少结束记录(EOF)"
            
            return True, f"文件验证通过，共 {record_count} 条记录"
            
        except Exception as e:
            return False, f"文件读取错误: {str(e)}"


def is_hex_file(file_path: str) -> bool:
    """判断是否为HEX文件"""
    if not file_path:
        return False
    
    # 检查文件扩展名
    if file_path.lower().endswith('.hex'):
        return True
    
    # 检查文件内容
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            first_line = f.readline().strip()
            return first_line.startswith(':')
    except:
        return False


def hex_to_bin(hex_file_path: str, bin_file_path: Optional[str] = None) -> Tuple[bool, str, bytes]:
    """
    将HEX文件转换为BIN文件
    
    Args:
        hex_file_path: HEX文件路径
        bin_file_path: BIN文件输出路径，如果为None则不保存文件
    
    Returns:
        (成功标志, 信息, 二进制数据)
    """
    parser = HexParser()
    
    if not parser.parse_file(hex_file_path):
        return False, "HEX文件解析失败", b''
    
    binary_data = parser.get_binary_data()
    
    if not binary_data:
        return False, "没有有效的二进制数据", b''
    
    # 如果指定了输出路径，保存BIN文件
    if bin_file_path:
        try:
            with open(bin_file_path, 'wb') as f:
                f.write(binary_data)
        except Exception as e:
            return False, f"保存BIN文件失败: {str(e)}", binary_data
    
    properties = parser.get_file_properties()
    info = f"转换成功，数据大小: {len(binary_data)} 字节，地址范围: {properties['起始地址']} - {properties['结束地址']}"
    
    return True, info, binary_data 